package main

import (
	"net/http"
	"tms-server/gin/controllers"
	"tms-server/gin/models"
	"tms-server/utils"

	"time"

	"tms-server/env"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

type (
	HandleFunc func(c *gin.Context) (res interface{}, e controllers.Error)

	Route struct {
		Path   string
		Method string
		Func   HandleFunc
	}

	RouteData struct {
		Group       *gin.RouterGroup
		Middlewares []gin.HandlerFunc
		Path        string
		Routes      []Route
	}
)

var (
	routeData = []RouteData{
		{
			Path: "/", Middlewares: []gin.HandlerFunc{},
			Routes: []Route{
				{"/", http.MethodGet, controllers.BasicContrl.HelloWorld},
				{"/login", http.MethodPost, controllers.BasicContrl.Login},
			},
		},
		{
			Path: "/", Middlewares: []gin.HandlerFunc{Auth},
			Routes: []Route{
				{"/upload", http.MethodPost, controllers.BasicContrl.Upload},

				{"/User.query", http.MethodGet, controllers.UserContrl.Query},
				{"/User.get", http.MethodGet, controllers.UserContrl.Get},
				{"/User.update", http.MethodPost, controllers.UserContrl.Update},
				{"/User.delete", http.MethodPost, controllers.UserContrl.Delete},

				{"/order/query", http.MethodGet, controllers.OrderContrl.Query},
				{"/order/find", http.MethodGet, controllers.OrderContrl.Find},
				{"/order/update", http.MethodPost, controllers.OrderContrl.Update},

				{"/auth/query", http.MethodGet, controllers.AuthContrl.Query},
				{"/auth/get", http.MethodGet, controllers.AuthContrl.Get},
				{"/auth/create", http.MethodPost, controllers.AuthContrl.Create},
				{"/auth/update", http.MethodPost, controllers.AuthContrl.Update},
				{"/auth/delete", http.MethodPost, controllers.AuthContrl.Delete},

				{"/role/query", http.MethodGet, controllers.RoleContrl.Query},
				{"/role/get", http.MethodGet, controllers.RoleContrl.Get},
				{"/role/create", http.MethodPost, controllers.RoleContrl.Create},
				{"/role/update", http.MethodPost, controllers.RoleContrl.Update},
				{"/role/delete", http.MethodPost, controllers.RoleContrl.Delete},
			},
		},
	}
)

func InitRouter() (router *gin.Engine) {
	router = gin.Default()

	authGroup := router.Group("/")
	for _, data := range routeData {
		// 注册路由组 && 注册路由组中间件
		data.Group = authGroup.Group(data.Path, data.Middlewares...)
		for _, middlewareFunc := range data.Middlewares {
			data.Group.Use(middlewareFunc)
		}
		data.Group.Use(cors.Default())

		for _, route := range data.Routes {
			data.Group.Handle(route.Method, route.Path, genHandler(route.Func))
		}
	}
	return
}

// genHandler 封装这一层是为了统计接口数据，以便打点
func genHandler(inHandler HandleFunc) gin.HandlerFunc {
	return func(c *gin.Context) {
		res, e := inHandler(c)
		if e.ErrCode != 0 {
			c.Status(e.StatusCode)
			c.JSON(e.StatusCode, []interface{}{e.ErrCode, e.ErrInfo})
		} else {
			c.JSON(e.StatusCode, []interface{}{0, res})
		}
		utils.Debug("request:", c.Request.PostForm)
		utils.Debug("response:", e, res)
	}
}

func Auth(c *gin.Context) {
	return
	// 签名验证
	token, _ := c.Cookie("userId")
	if token == "" {
		c.AbortWithStatusJSON(200, []interface{}{2, "请先登录"})
		return
	}
	userSecert := new(controllers.UserSecert)
	err := utils.Decrypt(token, env.Confs.APPSecret, userSecert)
	if err != nil {
		c.AbortWithStatusJSON(200, []interface{}{2, "解析失败，请重新登录"})
		return
	}

	if userSecert.UID <= 0 {
		c.AbortWithStatusJSON(200, []interface{}{2, "用户不存在，请重新登录"})
		return
	}
	now := time.Now()
	if now.After(userSecert.ExpiredAt) {
		c.AbortWithStatusJSON(200, []interface{}{2, "您已长时间离线，请重新登录"})
		return
	}

	// 权限验证
	uri := c.Request.URL.Path
	auth := env.APIAuthes[uri]
	if auth != "" {
		user, err := models.FindUserByID(userSecert.UID)
		if err != nil {
			c.AbortWithStatusJSON(200, []interface{}{2, err.Error()})
			return
		}
		authInfos, err := models.FindAuthesByDepId(user.Depid)
		if err != nil {
			c.AbortWithStatusJSON(200, []interface{}{2, err.Error()})
			return
		}
		var inAuth bool
		for _, authInfo := range authInfos {
			if authInfo.Authority.Name == auth {
				inAuth = true
				break
			}
		}
		if !inAuth {
			c.AbortWithStatusJSON(200, []interface{}{2, "权限不足"})
			return
		}
	}

	c.Set("playerId", userSecert.UID)
	c.Set("platform", userSecert.Platform)
}
